﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;
using TA.DotNetUtils;

public static class _ControlExtensions
{
	/// <summary>
	/// Gets true if current control is instantiated in designer, otherwise false.
	/// </summary>
	/// <param name="cThis"></param>
	/// <returns></returns>
	public static bool get_IsDesignMode(this Control cThis)
	{
		return (bool)_pDesignMode.GetValue(cThis, null);
	}
	/// <summary>
	/// Returns true if this is above the specified control in the control tree.
	/// </summary>
	/// <param name="cThis"></param>
	/// <param name="control"></param>
	/// <returns></returns>
	public static bool IsAscendantOf(this Control cThis, Control control)
	{
		while (control != null)
		{
			if (cThis == control) return true;
			control = control.Parent;
		}
		return false;
	}
	/// <summary>
	/// Gets the closest control in the control tree "above" this control which is of the specified type.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="This"></param>
	/// <returns></returns>
	public static T GetAscendant<T>(this Control This)
		where T : Control
	{
		Control c = This;
		while (c != null && !(c is T))
		{
			c = c.Parent;
		}
		return c as T;
	}
	/// <summary>
	/// Performs the specified action for each control in this control's sub-tree recursively. Warning: this might be expensive.
	/// </summary>
	/// <param name="cThis"></param>
	/// <param name="action"></param>
	public static void ForEachRecursive(this Control cThis, Action<Control> action)
	{
		foreach (Control c in cThis.Controls)
		{
			action(c);
			c.ForEachRecursive(action);
		}
	}
	/// <summary>
	/// Performs the specified action for those controls in this control's sub-tree that are of type T. Warning: this might be expensive.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="cThis"></param>
	/// <param name="action"></param>
	public static void ForEachRecursive<T>(this Control cThis, Action<T> action) where T : Control
	{
		foreach (Control c in cThis.Controls)
		{
			if (c is T)
				action((T)c);
			c.ForEachRecursive<T>(action);
		}
	}
	/// <summary>
	/// Performs the specified action for the first control in this control's sub-tree that is of type T. Warning: this might be expensive.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="cThis"></param>
	/// <param name="action">The action to be performed.</param>
	/// <returns>True if found a control of type T; false otherwise.</returns>
	public static bool ForEachRecursive(this Control cThis, Predicate<Control> action)
	{
		foreach (Control c in cThis.Controls)
		{
			if (action(c))
				return true;
			if (c.ForEachRecursive(action))
				return true;
		}
		return false;
	}
	/// <summary>
	/// Performs the specified action for those controls in this control's sub-tree that are of type T until the action delegate returns true, at which point the operation stops and method returns. Warning: this might be expensive.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="cThis"></param>
	/// <param name="action"></param>
	/// <returns></returns>
	public static bool ForEachRecursive<T>(this Control cThis, Predicate<T> action) where T : Control
	{
		foreach (Control c in cThis.Controls)
		{
			if (c is T)
			{
				if (action((T)c))
					return true;
			}
			if (c.ForEachRecursive<T>(action))
				return true;
		}
		return false;
	}
	/// <summary>
	/// Performs the specified action for those controls in this control's sub-tree that are of type T until the action delegate returns true, at which point the operation stops and method returns. Warning: this might be expensive.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="cThis"></param>
	/// <param name="action"></param>
	/// <returns></returns>
	public static bool ForEachRecursive<T>(this Control cThis, Func<T, RecursiveResult> action) where T : Control
	{
		foreach (Control c in cThis.Controls)
		{
			if (c is T)
			{
				switch (action((T)c))
				{
					case RecursiveResult.Abort:
						return true;
					case RecursiveResult.AvoidSubTree:
						continue;
				}
			}
			if (c.ForEachRecursive<T>(action))
				return true;
		}
		return false;
	}
	/// <summary>
	/// Performs the specified action for the first control in this control's sub-tree that is of type T. Warning: this might be expensive.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <param name="cThis"></param>
	/// <param name="action">The action to be performed.</param>
	/// <returns>True if found a control of type T; false otherwise.</returns>
	public static bool ForFirstRecursive<T>(this Control cThis, Action<T> action) where T : Control
	{
		foreach (Control c in cThis.Controls)
		{
			if (c is T)
			{
				action((T)c);
				return true;
			}
			if (c.ForFirstRecursive<T>(action))
				return true;
		}
		return false;
	}
	/// <summary>
	/// Tries finding a control by it's ID using the following starting points: this control, this control's parent, and the page.
	/// </summary>
	/// <param name="cThis"></param>
	/// <param name="id"></param>
	/// <returns></returns>
	public static Control FindControlGlobal(this Control cThis, string id)
	{
		if (string.IsNullOrEmpty(id)) return null;
		Control c;

		//if (HttpContext.Current != null && HttpContext.Current.Handler is THandler)
		//{
		//  THandler th = (THandler)HttpContext.Current.Handler;
		//  return th.FindControl(id);
		//}

		if ((c = cThis.FindControl(id)) != null)
			return c;
		if (cThis.Parent != null && (c = cThis.Parent.FindControl(id)) != null)
			return c;
		//if ((c = cThis.FindControlRecursive(id)) != null)
		//  return c;
		//if (cThis.Parent != null && (c = cThis.Parent.FindControlRecursive(id)) != null)
		//  return c;

		if (cThis.Page != null && cThis != cThis.Page)
		{
			if ((c = cThis.Page.FindControl(id)) != null)
				return c;
			//if ((c = cThis.Page.FindControlRecursive(id)) != null)
			//  return c;
		}
		return null;
	}
	/// <summary>
	/// Finds a control by recursively searching this control's sub-tree. Warning: this might be expensive.
	/// </summary>
	/// <param name="cThis"></param>
	/// <param name="id"></param>
	/// <returns></returns>
	public static Control FindControlRecursive(this Control cThis, string id)
	{
		if (string.IsNullOrEmpty(id)) return null;
		foreach (Control c in cThis.Controls)
		{
			if (string.Equals(c.ID, id))
				return c;
			Control t;
			if ((t = c.FindControlRecursive(id)) != null)
				return t;
		}
		return null;
	}
	public static bool get_IsVisible(this Control This)
	{
		while (This != null)
		{
			if (!This.Visible) return false;
			This = This.Parent;
		}
		return true;
	}
	public static bool get_IsInTree(this Control This)
	{
		Page p = This.Page;
		if (p == null) return false;
		Control c = This;
		while (c != null && c != p)
		{
			c = c.Parent;
		}
		return c == p;
	}
	public static void SetEnabledRecursive(this Control cThis, bool enabled)
	{
		cThis.ForEachRecursive<WebControl>(delegate(WebControl c) { c.Enabled = enabled; });
	}
	public static bool Contains(this Control cThis, Control child)
	{
		while (child != null)
		{
			if (child == cThis) return true;
			child = child.Parent;
		}
		return false;
	}
	public static string GetRelativeId(this Control This, Control startingPoint)
	{
		Control cur = This;
		StringBuilder sb = new StringBuilder(This.ID);
		while (cur.NamingContainer != startingPoint.NamingContainer)
		{
			if (cur.NamingContainer == cur.Page || cur.NamingContainer == cur || cur.NamingContainer == null)
				return null;

			sb.Insert(0, "$");
			sb.Insert(0, cur.NamingContainer.ID);

			cur = cur.NamingContainer;
		}

		return sb.ToString();
	}
	static readonly PropertyInfo _pDesignMode = typeof(Control).GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic);
}
